#include "los.h"
#include <stdio.h>
#include <stdlib.h>

pLOSConfiguration initLOSConfiguration(PalgConfiguration pALGconfig) {
	pLOSConfiguration result = malloc(sizeof(LOSConfiguration));
	checkMalloc(result, "los.h:initLOSConfiguration:1");
	result->evaluate = pALGconfig->evaluate;
	result->addEdgeTenure = pALGconfig->addEdgeTenure;
	result->removeEdgeTenure = pALGconfig->removeEdgeTenure;
	return result;
}

//TODO in futuro sarà possibile passare 3 variabili di tipo pLOSConfiguration, una per ogni mossa ad esempio. per ora condividono la config
int solveLocalSearch(Pgraph pg, Psolution ps, int k, PtabooState pts, int move, TabooExpire now, pLOSConfiguration pLOSconfig){

	switch (move){
		case MOVE_ADD:{
			return solveAddNeighbourhood(pg, getVehicleStateInSolution(ps, k), ps->gMatrix, k, getTabooListInTabooState(pts, k), now, pLOSconfig, false);
		}
		case MOVE_SWAP:{
			return solveSwapNeighbourhood(pg, getVehicleStateInSolution(ps, k), ps->gMatrix, k, getTabooListInTabooState(pts, k), now, pLOSconfig, false);
		}
		case MOVE_REMOVE:{ /* TODO è possibile gestire l'ultimo bool del prototipo a livelli superiori!
							REMEMBER: così com'è (false), NIENTE VIENE TOCCATO RISPETTO A QUANTO PROGETTATO. */
			return solveRemoveNeighbourhood(pg, getVehicleStateInSolution(ps, k), ps->gMatrix, k, getTabooListInTabooState(pts, k), now, pLOSconfig, false);
		}
		default:{
			fprintf(stderr,"mossa non accettata. exit\n");
			return -1;
		}
	}
}

int getDeltaTimeRemovingEdgeID(Pgraph pg,PedgeID toremove){
	return -getEdgeGraph(pg,toremove)->t;
}

int getDeltaTimeAddingEdgeID(Pgraph pg,PedgeID toadd){
	return getEdgeGraph(pg,toadd)->t;
}

int getDeltaLoadAddingEdgeID(Pgraph pg,PedgeID toadd,PGMatrix pgmat){
	return !(isEdgeGathered(pgmat,toadd))*getEdgeGraph(pg,toadd)->d;
}

int getDeltaLoadRemovingEdgeID(Pgraph pg,PedgeID toremove, int k,PGMatrix pgmat, PvehicleState pstate){
	return -amIGatheringEdge(pgmat,toremove,k)*(isEdgeWalkedOnceInVehiclePath(toremove,pstate->pvp))*getEdgeGraph(pg,toremove)->d;
}


PedgePair getEdgeTriangles(EdgeID e_ij, int N) {

	PedgePair result = malloc((N-2)*sizeof(EdgePair));
	checkMalloc(result,"los.c:getNearEdgePairs:1");
	int l; //index sugli archi

	for(l=0; l<e_ij.i; l++) { // l<i   (invert e_il)
		result[l].e_il.i = l;
		result[l].e_il.j = e_ij.i;
		result[l].e_jl.i = e_ij.j;
		result[l].e_jl.j = l;
	}
	for(l=e_ij.i+1; l<e_ij.j; l++) {  // i<l<j   (invert e_jl)
		result[l-1].e_il.i = e_ij.i;
		result[l-1].e_il.j = l;
		result[l-1].e_jl.i = l;
		result[l-1].e_jl.j = e_ij.j;
	}
	for(l=e_ij.j+1; l<N; l++) {		  // j<l
		result[l-2].e_il.i = e_ij.i;
		result[l-2].e_il.j = l;
		result[l-2].e_jl.i = e_ij.j;
		result[l-2].e_jl.j = l;
	}
	return result;
}

PedgeID getEdgeTriangulating(PedgeID pe_il, PedgeID pe_jl) {
	PedgeID pe_ij = malloc(sizeof(EdgeID));
	int shared = getSharedNode(pe_il, pe_jl);
	if(shared==NO_SHARED_NODE) { //FIXME magari e' meglio mettere come precondizione il fatto che i due archi siano consecutivi
		printf("\n\nchiamata edgeTriangulating con nodi non triangolanti. Sto restituendo un ptr NULLO.\n");
		return 0;
	}

	if (pe_il->i == shared)
		pe_ij->i = pe_il->j;
	else
		pe_ij->i = pe_il->i;

	if (pe_jl->i == shared)
		pe_ij->j = pe_jl->j;
	else
		pe_ij->j = pe_jl->i;

	validateEdgeID(pe_ij);
	return pe_ij;
}
